using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows.Forms;
using SG.Sys.Console.Process;
using SG.Sys.Console.View;

namespace SG.Sys.Console.Tab
{
    [Export(typeof(ITabManager))]
    class TabManager : ITabManager
    {
        public event EventHandler<TitleChangedEventArgs> OnTitleChanged;

        private TabControl _control;
        private string _newTabPageName;

        public TabControl Control
        {
            get { return _control; }
            set
            {
                _control = value;
                _control.Selected += ControlSelected;
                _newTabPageName = _control.TabPages[0].Name;
            }
        }

        void ControlSelected(object sender, EventArgs e)
        {
            var tab = _control.SelectedTab;
            string title;

            if (IsNewTabPage(tab))
            {
                title = tab.Text;
            }
            else
            {
                var pane = tab.GetPane();
                if (pane == null) return;

                title = pane.Wrapper.Title;
                pane.FocusInput();
            }
            FireTitleChange(new TitleChangedEventArgs(title));
        }

        private void FireTitleChange(TitleChangedEventArgs title)
        {
            var copy = OnTitleChanged;
            if (copy != null)
                copy(this, title);
        }

        public void NewTab(IProcessWrapper processWrapper)
        {
            var page = new TabPage(processWrapper.Name);
            IConsolePane consolePane = page.FillWith(new ConsolePane());
            consolePane.Initialize(processWrapper);
            consolePane.OnTitleChanged += consolePane_OnTitleChanged;
            consolePane.OnClose += consolePane_OnClose;  

            _control.TabPages.Insert(Math.Max(0, _control.TabCount-1), page);
            _control.SelectTab(page);
            ControlSelected(this, new EventArgs());
            consolePane.FocusInput();
        }

        public TabPage NewTabPage { get { return _control.TabPages[_newTabPageName]; } }

        void consolePane_OnClose(object sender, EventArgs e)
        {
            var tabPage = GetTabFromEvent(sender);
            if (tabPage != null)
                _control.TabPages.Remove(tabPage);

            if (_control.TabCount == 0 || _control.TabCount == 1 && IsNewTabPage(0))
                Application.Exit();
        }

        void consolePane_OnTitleChanged(object sender, TitleChangedEventArgs e)
        {
            var tabPage = GetTabFromEvent(sender);
            if (tabPage != null && _control.SelectedTab == tabPage)
                FireTitleChange(e);
        }

        private TabPage GetTabFromEvent(object sender)
        {
            var consolePane = (ConsolePane) sender;
            var tabName = consolePane.Wrapper.Name;
            var findPage =
                from TabPage page in _control.TabPages
                where page.Text == tabName
                select page;

            var tabPage = findPage.SingleOrDefault();
            return tabPage;
        }

        public void SendClose()
        {
            var copyList = new List<TabPage>();
            for (var i = 0; i < _control.TabCount; i++) 
                if (!IsNewTabPage(i)) 
                    copyList.Add(IndexToPage(i));

            foreach (var page in copyList)
                page.GetPane().SendClose();
        }

        public void AutoLoadTabs()
        {
            var autoLoadable =
                from factoryData in Program.Instance.ProcessWrapperFactories
                where factoryData.Metadata.AutoLoad
                select factoryData.Value;

            foreach (var factory in autoLoadable)
                NewTab(factory.NewProcessWrapper());
        }

        private TabPage IndexToPage(int pageIndex)
        {
            return _control.TabPages[pageIndex];
        }

        private bool IsNewTabPage(int pageIndex)
        {
            return IsNewTabPage(IndexToPage(pageIndex));
        }
        private bool IsNewTabPage(TabPage page)
        {
            return page.Name == _newTabPageName;
        }

        private IConsolePane GetPane(int pageIndex)
        {
            return IndexToPage(pageIndex).GetPane();
        }
    }
}